#pragma once
#include<iostream>
#include<string>
#include<filesystem>
#include<sstream>
#include<fstream>
#include<memory>
#include<unistd.h>
#include"Lock.hpp"

#define gsep "\r\n"
#define defaultname "mylog.log"
#define defaultpath "./"
//首先定义一个策略类
class LogStrategy
{
    public:
    LogStrategy()
    {}
    virtual void Strategy(std::string message)=0;
    ~LogStrategy()
    {}
};

//向显示器打印日志信息
class ConsoleLogStrategy:public LogStrategy
{
    public:
    ConsoleLogStrategy()
    {}
    ~ConsoleLogStrategy()
    {}
    void Strategy(std::string message)
    {
        LockGuard lock(_mutex);
        std::cout<<message<<gsep;
    }
    private:
    Mutex _mutex;
};

//向指定文件打印指定信息
class FileLogStrategy:public LogStrategy
{
    public:
    FileLogStrategy(std::string path=defaultpath,std::string name=defaultname)
    :_path(path)
    ,_name(name)
    ,_mutex()
    {
        //首先检查路径是否存在，不存在就创建
        if(!std::filesystem::exists(_path))
        {
            std::filesystem::create_directories(_path);
        }
        _filepath=_path+(_path.back()=='/'?"":"/")+_name;
        std::cout<<_filepath<<std::endl;
    }
    ~FileLogStrategy()
    {}
    void Strategy(std::string message)
    {
        LockGuard lock(_mutex);
        std::ofstream out(_filepath.c_str(),std::ios::app);
        if(out.is_open())
        {
            out.write(message.c_str(),message.size());
        }
        out.close();
    }
    private:
    std::string _path;
    std::string _name;
    std::string _filepath;
    Mutex _mutex;
};


enum LogLevel
{
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

std::string Getlevel(LogLevel& level)
{
    switch (level)
    {
    case LogLevel::DEBUG:
        return "DEBUG";
    case LogLevel::INFO:
        return "INFO";
    case LogLevel::WARNING:
        return "WARNING";
    case LogLevel::ERROR:
        return "ERROR";
    case LogLevel::FATAL:
        return "FATAL";
    default:
        return "UNKNOW";
    }
}
std::string Getcurr_time()
{
     time_t tm = time(nullptr);
        struct tm curr;
        localtime_r(&tm, &curr);
        // 这⾥如果不好看，可以考sprintf 
        // ⽅法1 
        // std::stringstream ss;
        // ss << curr.tm_year + 1900 << "-" << curr.tm_mon << "-" << curr.tm_mday << " "
        //    << curr.tm_hour << ":" << curr.tm_min << ":" << curr.tm_sec;
        // return ss.str();
        // ⽅法2 
        char timebuffer[64];
        snprintf(timebuffer, sizeof(timebuffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr.tm_year + 1900,
                 curr.tm_mon,
                 curr.tm_mday,
                 curr.tm_hour,
                 curr.tm_min,
                 curr.tm_sec);
        return timebuffer;
}
class Logger
{
    public:
    Logger()
    {
        Enable_ConsoleLogStrategy();
    }
    void Enable_FileLogStrategy()
    {
        _fflush_LogStrategy=std::make_unique<FileLogStrategy>();
    }
    void Enable_ConsoleLogStrategy()
    {
        _fflush_LogStrategy=std::make_unique<ConsoleLogStrategy>();
    }
    class log_message
    {
        public:
        log_message(LogLevel level,std::string filename,int linenum,Logger& logger)
        :_level(Getlevel(level))
        ,_curr_time(Getcurr_time())
        ,_pid(getpid())
        ,_filename(filename)
        ,_linenum(linenum)
        ,_logger(logger)
        {
            //合并左半部分
            std::stringstream ss;
            ss<<"["<<_curr_time<<"] "
            <<"["<<_level<<"] "
            <<"["<<_pid<<"] "
            <<"["<<_filename<<"] "
            <<"["<<_linenum<<"] "
            <<"- ";
            _tatolmessage=ss.str();
        }
        template<class T>
        log_message& operator <<(const T& message)
        {
            std::stringstream ss;
            ss<<message;
            _tatolmessage+=ss.str();
            return *this;
        }

        ~log_message()
        {
            _logger._fflush_LogStrategy->Strategy(_tatolmessage);
        }
        private:
        std::string _level;
        std::string _curr_time;
        pid_t _pid;
        std::string _filename;
        int _linenum;
        std::string _tatolmessage;
        Logger& _logger;
    };
    ~Logger()=default;
    log_message operator ()(LogLevel level,std::string filename,int linenum)
    {
        //返回一个匿名对象：
        return log_message(level,filename,linenum,*this);
    }
    private:
    std::unique_ptr<LogStrategy> _fflush_LogStrategy;
};

Logger logger;
#define LOG(level) logger(level,__FILE__,__LINE__)
#define Enable_Console_Log_Strategy() logger.Enable_ConsoleLogStrategy()
#define Enable_File_Log_Strategy() logger.Enable_FileLogStrategy()